﻿#include "StdAfx.h"
#include "Globals.h"
#include "MainFunctions.h"

#pragma comment(lib, "Winmm.lib")

std::ofstream		logfile("log.txt", std::ios::out);
CRITICAL_SECTION	logfileAccess;

//-----------------------------------------------------------------------------
double UpdateCaption(LPCWSTR text)
{
	static std::wstringstream	caption;
	static Counter					timer;
	static __int64					prevTime	= timer.Get();
	static DWORD					frames	= 0;
	static double					fps		= 0;

//----
	__int64 currTime = timer.Get();
	frames++;

	double seconds =  timer.getPeriod() * (currTime - prevTime);

//----
	if(seconds >= 1.0)
	{
		fps = frames / seconds;
		prevTime = currTime;
		frames = 0;

		caption.str(L"");
		caption << L"Project Tea Time - " << 0.01*int(100.0*fps+0.5) << L" fps";

		if(text)
			caption << L" - " << text;

	//----
		SetWindowText(PTT::wnd->getHWND(),caption.str().c_str());
	}

	return fps;
}


//-----------------------------------------------------------------------------
int GL_Test()
{
	using namespace PTT;

	wnd->show();

	GraphicsFile	texFile	(L"graphics/chance time.png"),
						whiteFile(L"graphics/chance time white.png");
	Texture			cat		(L"graphics/cat.png"),
						t1			(texFile),
						t2			(whiteFile);

	RECT window;
	GetClientRect(wnd->getHWND(),&window);
	glViewport(window.left, window.top, window.right, window.bottom);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, window.right, window.bottom, 0, -1.0, 1.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glClearColor(0, 0, 0, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//----


	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	white.glApply();
	cat.draw();

	glColor4f(1.0f, 1.0f, 1.0f, 1.0f);

	t1.draw(0, 50, 1.0f);

//----
	glFlush();
	SwapBuffers(wnd->getDC());

	Sleep(2000);
	SwapBuffers(wnd->getDC());

	glBlendFunc(GL_SRC_ALPHA, GL_ONE);

	glColor4f(1.0f, 1.0f, 0.0f, 0.5f);
	t1.draw(0, 50, 1.0f);
/*
	glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);

	glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
	t2.draw(0, 200, 1.0f);
*/

//----
	glFlush();
	SwapBuffers(wnd->getDC());

	Sleep(8000);
	return 0;
}


//-----------------------------------------------------------------------------
//	By setting linker subsystem to "Windows", the console window can be removed.
int _tmain(int argc, _TCHAR* argv[])
//int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int numCmd)
{
	InitializeCriticalSectionAndSpinCount(&logfileAccess, 800);

//----
//	Set buffer for cout
	char buf[1024];
	HRESULT result = setvbuf(stdout, buf, _IOLBF, 1024);
	LOG("setvbuf = " << result);

//	Set maximum resolution of system timer, to potentially increase the accuracy of "Sleep()"
	TIMECAPS timeCaps;
	MMRESULT timeCapsResult = timeGetDevCaps(&timeCaps, sizeof(timeCaps));
	if(timeCapsResult==MMSYSERR_NOERROR)
	{
		timeCapsResult = timeBeginPeriod(timeCaps.wPeriodMin);
		LOG("timeBeginPeriod = " << timeCapsResult);
	}

// Initialize the COM library for use by this thread
	result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
	LOG("CoInitializeEx = " << result);

//	Initialize GDI+.
	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
	ULONG_PTR gdiplusToken;
	Gdiplus::Status status = Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
	LOG("GdiplusStartup = " << status);

	XINPUT_VIBRATION vibration = {0};
	result = XInputSetState(0, &vibration);
	LOG("XInputSetState = " << result);

//	Initialize ffmpeg
	avcodec_register_all();
	LOG("avcodec_register_all");
	av_register_all();
	LOG("av_register_all");

//----
//	Create window, initialize opengl and xaudio, load osu files and some graphics, etc.
	PTT::InitGlobals();

	LOG("InitGlobals done.");

//	return GL_Test();

	if(PTT::wnd==NULL)
		Error(L"Couldn't create window");

	PTT::wnd->addReference();
	LOG("Added window reference.");

	if(PTT::UseAudio)
		PTT::audio->getMasteringVoice()->SetVolume(0.01f*PTT::MasterVolume);
	LOG("SetVolume done.");

//----
//	Start preview thread
	CreateThread(NULL, 0, PreviewThread, NULL, 0, NULL);
	LOG("Created PreviewThread.");

//----
//	Start genetic algorithm testing thread
	CreateThread(NULL, 0, TestingThread, NULL, 0, NULL);
	LOG("Created TestingThread.");

//----
//	Start timing and input thread and video thread
	CreateThread(NULL, 0, InputThread, NULL, 0, NULL);
	CreateThread(NULL, 0, VideoThread, NULL, 0, NULL);
	LOG("Created InputThread and VideoThread.");

//----
	PTT::wnd->show();
	LOG("Shown Window.");

//----
//	Default OpenGL state should be restored when changed.
	glHint	(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
	glHint	(GL_LINE_SMOOTH_HINT,    GL_NICEST);
	glEnable	(GL_POLYGON_SMOOTH);
	glEnable	(GL_LINE_SMOOTH);
	glEnable	(GL_BLEND);
	glEnable	(GL_TEXTURE_2D);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	LOG("Starting main loop.");

//----
//	Main loop
	for(;;)
	{
	//----
	//	Blocking call to select song
		SelectSong();
		LOG("Selected song.");
		if(PTT::wnd->isQuitting())
			break;


	//----
	//	Blocking call to play song
		PlaySong();
		LOG("Played song.");
		if(PTT::wnd->isQuitting())
			break;
	}

//~~~~
//	point of no return

//----
//	Tell the threads to exit and wait for them
	ExitTestingThread();				LOG("Exited TestingThread.");
	ExitInputAndVideoThread();		LOG("Exited InputThread and VideoThread.");
	ExitPreviewThread();				LOG("Exited PreviewThread.");


// Let the window know it's no longer needed
	PTT::wnd->removeReference();

//----
//	All audio threads should be gone by now, so we can release xaudio and other globals
	PTT::DeleteGlobals();
	LOG("Deleted global variables.");

//----
	XInputSetState(0, &vibration);
	Gdiplus::GdiplusShutdown(gdiplusToken);	LOG("Shut down Gdiplus.");
	CoUninitialize();									LOG("Uninitialized COM.");

	if(timeCapsResult==MMSYSERR_NOERROR)
		timeEndPeriod(timeCaps.wPeriodMin);

	DeleteCriticalSection(&logfileAccess);

	return 0;
}


